import logging
import copy
from datetime import timedelta, datetime
from common.timeutil import get_interval_end_pair
from common.mg_core.mg import insert_or_update, get_report_template, get_report
from common.es_core.user_filter import UserFilter
from common.account import db as account_db
from event_rule.dwc.product_event_rule.bet_user_analysis import BET_USER_ANALYSIS_CONFIG
from event_rule.dwc.product_event_rule.fish_profit_report import FISH_PROFIT_REPORT
from common.dwc.maestro.const import FISH_TYPE
from common.es_core.report_creator import ReportCreator, UserReportCreator
from common.es_core.es_interface import es_search_interface
from common.const import INTERVAL_TYPE_MAPPER
from .const import GAME_DCT

_LOGGER = logging.getLogger(__name__)


def _get_aggregate_report_dynamic_argument_dct(index, start_time, end_time, target_event_id,
                                               custom_filter=None, custom_not_filter=None):
    # 今日投注帳號
    user_filter = UserFilter(merchant_name=index)
    user_filter.event_user_filter('bet_order', start_time, end_time, custom_filter=custom_filter,
                                  custom_not_filter=custom_not_filter)
    today_bet_user = user_filter.get_user_pool()
    user_filter.event_user_filter(['bet_order'], start_time, end_time,
                                  custom_filter=custom_filter + [{"term": {"_is_new_user": 1}}],
                                  custom_not_filter=custom_not_filter)
    today_bet_new_user = user_filter.get_user_pool()
    # 赢家盈亏
    profit_user_filter = UserFilter(merchant_name=index)
    profit_user_filter.stage_filter(
        target_event_id, ['bet_order_award_amount', '-bet_order_bet_amount'],
        'sum', start_time, end_time, 0, custom_filter=custom_filter, custom_not_filter=custom_not_filter
    )
    profit_user_pool = profit_user_filter.get_user_pool()
    # 输家盈亏，非贏即輸
    lose_user_pool = list(set(today_bet_user) - set(profit_user_pool))
    # 新增投注账号
    user_filter = UserFilter(merchant_name=index, user_pool=list(set(today_bet_user) - set(today_bet_new_user)))
    user_filter.stage_filter("bet_order", 'bet_order_bet_amount', 'value_count',
                             start_time - timedelta(days=3650), start_time, 0, None, custom_filter=custom_filter,
                             custom_not_filter=custom_not_filter)
    first_bet_user = list(set(today_bet_user) - set(user_filter.get_user_pool()))
    # 今日充值账号
    user_filter = UserFilter(merchant_name=index)
    user_filter.event_user_filter('recharge', start_time, end_time, custom_filter=custom_filter,
                                  custom_not_filter=custom_not_filter)
    recharge_user = user_filter.get_user_pool()
    dynamic_target_users_dct = dict(
        profit_user_pool=profit_user_pool,
        lose_user_pool=lose_user_pool,
        first_bet_user=first_bet_user,
        recharge_user=recharge_user
    )
    return dynamic_target_users_dct


def _add_event(event_id, custom_filter=None):
    custom_filter_tmp = []
    if custom_filter:
        custom_filter_tmp = [
            {
                "bool": {
                    "should": [
                        {
                            "bool": {
                                "must": custom_filter
                            }
                        },
                        {
                            "term": {
                                "_event_id": event_id
                            }
                        }
                    ]
                }
            }
        ]
    return custom_filter_tmp


def get_game_limit(index, game_sub_type, game_third_type, start_time, end_time):
    query_dct = {
        "query": {
            "bool": {
                "filter": [
                    {"term": {"bet_order_sub_type.keyword": game_sub_type}},
                    {"terms": {"bet_order_third_type.keyword": game_third_type}},
                    {"range": {"_event_time": {"gte": int(start_time.timestamp()), "lt": int(end_time.timestamp())}}},
                    {"term": {"bet_order_user_type": 0}}
                ]
            }
        },
        "size": 1
    }
    res = es_search_interface(index, query_dct)
    if not res['hits']['hits']:
        return
    if 'bet_order_limit' in res['hits']['hits'][0]['_source']:
        return res['hits']['hits'][0]['_source']['bet_order_limit']
    return res['hits']['hits'][0]['_source']['bet_order_third_type']


def _create_game_aggregate_report(index, start_time, end_time, custom_filter, custom_not_filter,
                                  base_user_pool, event_rule, base_report_template, limit=None):
    collection = '_'.join(['game', 'aggregate', 'report'])
    dynamic_argument_dct = _get_aggregate_report_dynamic_argument_dct(
        index, start_time, end_time, 'bet_order', custom_filter=custom_filter, custom_not_filter=custom_not_filter
    )
    report_template = copy.deepcopy(base_report_template)
    report_template_group_by = copy.deepcopy(base_report_template)
    report_template['_id'] = '-'.join(['all', report_template['_id']])
    if limit:
        report_template['limit'] = limit
    game_aggregate_report = UserReportCreator.create_user_report(
        start_time=start_time, end_time=end_time, event_rule=event_rule, index=index, custom_filter=custom_filter,
        custom_not_filter=custom_not_filter, dynamic_argument_dct=dynamic_argument_dct, user_pool=base_user_pool,
        to_group=True, sum_up=True)
    report_template.update({event_rule.get('group_by').replace('.keyword', ''): 'all'})
    report_template.update(game_aggregate_report['sum_up'])
    insert_or_update(report_template, database=index, collection=collection)
    for report in game_aggregate_report['list']:
        report_template_group_by['_id'] = '-'.join(
            [report[event_rule.get('group_by').replace('.keyword', '')], report_template_group_by['_id']])
        report_template_group_by.update(report)
        insert_or_update(report_template_group_by, database=index, collection=collection)


def game_aggregate_report_handler(interval_type, base_time, last_window, event_rule, index):
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window)
    base_user_pool = None
    day = str(start_time).split(' ')[0] if interval_type.value == 'day' else str(start_time).split(':')[0]
    report_id = '-'.join(['all', day, interval_type.value])
    report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
    report_template.update(dict(game_id='all', game_name='汇总', room_id='all', room_name='汇总'))
    custom_not_filter = [{'term': {"bet_order_user_type": 1}}]
    _create_game_aggregate_report(index, start_time, end_time, custom_filter=[], custom_not_filter=custom_not_filter,
                                  base_user_pool=base_user_pool, event_rule=event_rule,
                                  base_report_template=report_template)
    for game_dct in GAME_DCT.get(index, []):
        game_id = game_dct.get('key')
        custom_filter = [{"term": {"bet_order_sub_type.keyword": game_id}}]
        custom_filter_tmp = _add_event('recharge', custom_filter)
        report_id = '-'.join([game_id, 'all', day, interval_type.value])
        report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
        report_template.update(dict(game_id=game_id, game_name=game_dct.get("name", "-"), room_id='all',
                                    room_name='汇总'))
        _create_game_aggregate_report(index, start_time, end_time, custom_filter=custom_filter_tmp,
                                      custom_not_filter=custom_not_filter,
                                      base_user_pool=base_user_pool, event_rule=event_rule,
                                      base_report_template=report_template)
        for room_dct in game_dct.get('third_type', []):
            room_id = [room_dct.get('key')] if not isinstance(room_dct.get('key'), list) else room_dct.get('key')
            room_key = room_id[0]
            if index in ('dark3', 'dark4',):
                for each_id in copy.deepcopy(room_id):
                    room_id.append('_'.join([game_id, each_id]))
                room_key = room_id[1]
            limit = get_game_limit(index, game_id, room_id, start_time, end_time) or '-'
            report_id = '-'.join([game_id, room_key, day, interval_type.value])
            report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
            report_template.update(dict(game_id=game_id, game_name=game_dct.get("name", "-"), room_id=room_id,
                                        room_name=room_dct.get("name", '-')))
            custom_filter = [{"term": {"bet_order_sub_type.keyword": game_id}},
                             {"terms": {"bet_order_third_type.keyword": room_id}}]
            custom_filter_tmp = _add_event('recharge', custom_filter)
            _create_game_aggregate_report(index, start_time, end_time, custom_filter=custom_filter_tmp,
                                          custom_not_filter=custom_not_filter,
                                          base_user_pool=base_user_pool, event_rule=event_rule,
                                          base_report_template=report_template, limit=limit)


def get_game_aggregate_analysis_preset(merchant_name):
    game_dct = GAME_DCT.get(merchant_name, [])
    for game in game_dct:
        for room_dct in game.get('third_type', []):
            if isinstance(room_dct['key'], list):
                room_dct['key'] = room_dct['key'][0]
    return game_dct


def create_bet_user_event_rule(index, event_rule, report_type):
    assert report_type in ('bet', 'profit')
    assert len(event_rule['values']) == 1
    res_event_rule = copy.deepcopy(event_rule)
    template = res_event_rule['values'][0]
    for game_dct in GAME_DCT.get(index):
        item = copy.deepcopy(template)
        item['value_id'] = '_'.join([game_dct['key'], item['value_id']])
        item['value_name'] = game_dct['name'] + '投注' if report_type == 'bet' else '盈利'
        item['filter'].append({"term": {"bet_order_sub_type.keyword": game_dct['key']}})
        res_event_rule['values'].append(item)
    return res_event_rule


def bet_user_analysis_report_handler(interval_type, base_time, last_window, event_rule, index):
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window)
    base_user_pool = None
    day = str(start_time).split(' ')[0] if interval_type.value == 'day' else str(start_time).split(':')[0]
    report_id = '-'.join(['all', day, interval_type.value])
    report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
    report_template.update(dict(game_id='all', game_name='汇总', room_id='all', room_name='汇总'))
    _create_user_analysis_report(index, start_time, end_time, base_user_pool=base_user_pool, event_rule=event_rule,
                                 base_report_template=report_template)
    for game_dct in GAME_DCT.get(index, []):
        game_id = game_dct.get('key')
        custom_filter = [{"term": {"bet_order_sub_type.keyword": game_id}}]
        report_id = '-'.join([game_id, 'all', day, interval_type.value])
        report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
        report_template.update(dict(game_id=game_id, game_name=game_dct.get("name", "-"), room_id='all',
                                    room_name='汇总'))
        _create_user_analysis_report(index, start_time, end_time, base_user_pool=base_user_pool,
                                     base_custom_filter=custom_filter, event_rule=event_rule,
                                     base_report_template=report_template)
        for room_dct in game_dct.get('third_type', []):
            room_id = [room_dct.get('key')] if not isinstance(room_dct.get('key'), list) else room_dct.get('key')
            room_key = room_id[0]
            if index in ('dark3', 'dark4',):
                for each_id in copy.deepcopy(room_id):
                    room_id.append('_'.join([game_id, each_id]))
                room_key = room_id[1]
            report_id = '-'.join([game_id, room_key, day, interval_type.value])
            report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
            report_template.update(dict(game_id=game_id, game_name=game_dct.get("name", "-"), room_id=room_id,
                                        room_name=room_dct.get("name", '-')))
            custom_filter = [{"term": {"bet_order_sub_type.keyword": game_id}},
                             {"terms": {"bet_order_third_type.keyword": room_id}}]
            _create_user_analysis_report(index, start_time, end_time, base_custom_filter=custom_filter,
                                         base_user_pool=base_user_pool, event_rule=event_rule,
                                         base_report_template=report_template)


def _create_user_analysis_report(index, start_time, end_time, base_custom_filter=None,
                                 base_user_pool=None, event_rule=None, base_report_template=None):
    custom_filter = base_custom_filter + [{"term": {"bet_order_user_type": 0}}] if base_custom_filter else [
        {"term": {"bet_order_user_type": 0}}]
    collection = '_'.join(['game', 'bet_user_analysis', 'report'])
    user_analysis_report = ReportCreator.create_report(user_pool=base_user_pool, start_time=start_time,
                                                       end_time=end_time, event_rule=event_rule, index=index,
                                                       custom_filter=custom_filter, to_group=True, max_bucket=20000)
    user_id_list = [user_report['_user_id'] for user_report in user_analysis_report['list']]
    users, _ = account_db.list_user(index, {'user_id__in': user_id_list}, disable_paginate=True)
    user_dct = {str(user['user_id']): user for user in users}
    for user_report in user_analysis_report['list']:
        report_template = copy.deepcopy(base_report_template)
        report_template['_id'] = '-'.join([report_template['_id'], str(user_report['_user_id'])])
        user = user_dct.get(str(user_report['_user_id']), {})
        user_report['chn'] = user.get('channel', '未知')
        user_report['registered_at'] = str(user.get('registered_at', '未知'))
        report_template.update(user_report)
        insert_or_update(report_template, database=index, collection=collection)


def get_user_analysis_report(index, amount_max=None, amount_min=None, profit_amount_max=None, profit_amount_min=None,
                             user_id=None, chn_filter_list=None, time_range=None, registered_time_range=None,
                             game_id=None, game_id_list=None, disable_paginate=None, export_size_limit=200000,
                             sort_by=None, page=None, size=None, display_dimension=None):
    result_condition = dict()
    if amount_max is not None and amount_min is not None:
        assert amount_min <= amount_max
        result_condition['bet_amount'] = {'$gte': amount_min, '$lte': amount_max}
    elif amount_max is not None and amount_min is None:
        result_condition['bet_amount'] = {'$lte': amount_max}
    elif amount_max is None and amount_min is not None:
        result_condition['bet_amount'] = {'$gte': amount_min}
    if profit_amount_max or profit_amount_min:
        result_condition.setdefault('choushui', {})
        if profit_amount_min:
            result_condition['choushui']['$gte'] = profit_amount_min
        if profit_amount_max:
            result_condition['choushui']['$lte'] = profit_amount_max
    condition = dict()
    condition['game_id'] = {'$in': game_id}
    if user_id:
        condition['_user_id'] = {'$in': user_id}
    if chn_filter_list:
        condition['chn'] = {'$in': chn_filter_list}
    if game_id_list:
        condition['room_id'] = {'$in': game_id_list}
    condition['day'] = {'$gte': datetime.strftime(time_range[0], "%Y-%m-%d"),
                        '$lte': datetime.strftime(time_range[1], "%Y-%m-%d")}
    condition['registered_at'] = {'$gte': datetime.strftime(registered_time_range[0], '%Y-%m-%d %H:%M:%S'),
                                  '$lte': datetime.strftime(registered_time_range[1], '%Y-%m-%d %H:%M:%S')}
    (collection, event_rule) = ('game_bet_user_analysis_report', BET_USER_ANALYSIS_CONFIG)
    custom_group_by_field = {
        'registered_at': {"$first": '$registered_at'},
        'chn': {"$first": "$chn"},
        '_user_id': {"$first": "$_user_id"},
        'game_name': {"$first": "$game_name"},
        'room_name': {"$first": "$room_name"}
    }
    group_key = '_user_id'
    if len(game_id) > 1 and len(game_id_list) > 1:
        group_key = {'_user_id': '$_user_id', 'room_name': '$room_name'}
    if len(game_id) > 1 and "all" in game_id_list:
        group_key = {'_user_id': '$_user_id', 'game_name': '$game_name'}
    custom_value_by_field = None
    if not display_dimension and datetime.strftime(time_range[0], "%Y-%m-%d") != datetime.strftime(time_range[1],
                                                                                                   "%Y-%m-%d"):
        custom_value_by_field = {"day": "汇总"}
    merge_report = True
    if display_dimension:
        merge_report = False
    analysis_result, total_count = get_report(index, collection, condition, sort_key=sort_by, page=page, size=size,
                                              disable_paginate=disable_paginate,
                                              merge_report=merge_report, event_rule=event_rule,
                                              group_key=group_key, custom_group_by_field=custom_group_by_field,
                                              result_condition=result_condition,
                                              export_size_limit=export_size_limit,
                                              custom_value_by_field=custom_value_by_field)
    return analysis_result, total_count


def _get_distinct_fish_room(index, start_time, end_time):
    query_dsl = {
        "query": {
            "bool": {
                "filter": [
                    {"term": {"_event_id": "fishing_bet_item"}},
                    {"range": {"_event_time": {"gte": start_time.timestamp(), "lt": end_time.timestamp()}}}
                ]
            }
        },
        "size": 0,
        "aggs": {
            "distinct_fish_third_type": {
                "terms": {
                    "field": "fishing_bet_item_third_type.keyword"
                }
            }
        }
    }
    res = es_search_interface(index, query_dsl)
    buckets = res['aggregations']['distinct_fish_third_type']['buckets']
    return [e['key'] for e in buckets] + ['all']


def fish_profit_report_handler(interval_type, base_time, last_window, event_rule, index, display_only=None,
                               user_id=None):
    start_time, end_time = get_interval_end_pair(interval_type, base_time, last_window)
    day = str(start_time).split(' ')[0] if interval_type.value == 'day' else str(start_time).split(':')[0]
    collection = 'game_fish_report'
    distinct_fish_room = _get_distinct_fish_room(index, start_time, end_time)
    results = []
    for fish_room in distinct_fish_room:
        report_id = '-'.join([fish_room, 'all', day, interval_type.value])
        report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
        custom_filter = [{"term": {"fishing_bet_item_third_type": fish_room}}] if fish_room != 'all' else []
        if user_id is not None:
            custom_filter += [{"term": {"_user_id": user_id}}]
        report_template.update(
            UserReportCreator.create_user_report(start_time=start_time, end_time=end_time,
                                                 event_rule=event_rule, index=index, custom_filter=custom_filter)
        )
        report_template.update({event_rule.get('group_by').replace('.keyword', ''): 'all', 'room_id': fish_room})
        results.append(report_template)
        reports = UserReportCreator.create_user_report(
            start_time=start_time, end_time=end_time, event_rule=event_rule,
            index=index, custom_filter=custom_filter, to_group=True
        )
        for report in reports['list']:
            report_id = '-'.join([fish_room, report[event_rule.get('group_by').replace('.keyword', '')],
                                  day, interval_type.value])
            report_template = get_report_template(start_time, interval_type, custom_report_id=report_id)
            report_template.update({'room_id': fish_room})
            report_template.update(report)
            results.append(report_template)
    if not display_only:
        for e in results:
            insert_or_update(e, database=index, collection=collection)
    return results


def _get_fish_profit_user_report(index, time_range, user_id, interval_type=None, user_type=None,
                                 room_id=None, fish_type=None, sort_by=None, size=None, page=None,
                                 disable_paginate=None):
    results = []
    while time_range[0] < time_range[1]:
        user_results = fish_profit_report_handler(INTERVAL_TYPE_MAPPER[interval_type],
                                                  time_range[0] + timedelta(days=1), 1,
                                                  FISH_PROFIT_REPORT, index, display_only=True, user_id=user_id)
        user_results = [{**item, '_user_id': user_id} for item in user_results]
        results += user_results
        time_range[0] += timedelta(days=1)
    resp_items = []
    for e in results:
        if room_id and e['room_id'] not in room_id:
            continue
        if fish_type and e['fishing_bet_item_fish_type'] not in fish_type:
            continue
        if user_type:
            e.update(e[user_type])
        resp_items.append(e)
    if sort_by:
        sort_direction = 1 if sort_by[0] != '-' else -1
        sort_key = sort_by if sort_by[0] != '-' else sort_by[1:]
        resp_items = sorted(resp_items, key=lambda k: k[sort_key], reverse=False if sort_direction else False)
    start, end = (page - 1) * size, page * size
    return resp_items[start:end] if not disable_paginate else resp_items, len(resp_items)


FISH_ROOM = {"0": "新捕鱼新手场",
             "1": "新捕鱼初级场",
             "2": "新捕鱼中级场",
             "3": "新捕鱼高级场"}


def _process_fish_profit_report(fish_profit_report):
    for e in fish_profit_report:
        e['room_id'] = FISH_ROOM.get(e['room_id'], '汇总')
        e['fishing_bet_item_fish_type'] = FISH_TYPE.get(
            int(e['fishing_bet_item_fish_type']) if e['fishing_bet_item_fish_type'] != 'all'
            else e['fishing_bet_item_fish_type'], '汇总')
    return fish_profit_report


def get_fish_profit_report(index, time_range=None, user_id=None, interval_type=None, user_type=None,
                           room_id=None, fish_type=None, sort_by=None, size=None, page=None, disable_paginate=None):
    if not user_id:
        condition = dict(updated_at={'$gte': time_range[0], '$lt': time_range[1]}, interval_type=interval_type)
        if room_id:
            condition['room_id'] = {'$in': room_id}
        if fish_type:
            condition['fishing_bet_item_fish_type'] = {"$in": fish_type}
        res, total_count = get_report(index, 'game_fish_report', condition, sort_key=sort_by, page=page,
                                      size=size, disable_paginate=disable_paginate, user_type=user_type)
        return _process_fish_profit_report(res), total_count
    res, total_count = _get_fish_profit_user_report(index, time_range, user_id, interval_type=interval_type,
                                                    user_type=user_type, room_id=room_id, fish_type=fish_type,
                                                    sort_by=sort_by, size=size, page=page,
                                                    disable_paginate=disable_paginate)
    return _process_fish_profit_report(res), total_count


def get_fish_profit_analysis_preset():
    return dict(fish_types=FISH_TYPE, rooms=FISH_ROOM)
